package net.daoke.relation.service;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.daoke.relation.model.domain.NetworkRelation;
import net.daoke.relation.model.domain.NodeDomain;
import net.daoke.relation.model.request.AddNetRelationVO;
import net.daoke.relation.repository.NodeRepository;
import net.daoke.relation.repository.RelationshipRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Optional;

@Slf4j
@Service
@AllArgsConstructor
public class NetworkService {

    private final NodeRepository nodeRepository;
    private final RelationshipRepository relationshipRepository;

    /**
     * 添加网络关系
     *
     * @param addNetRelationVO 包含添加网络关系所需信息的VO对象
     * @return 添加后的网络关系对象
     */
    @Transactional
    public NetworkRelation addNetworkRelation(AddNetRelationVO addNetRelationVO) {
        // 1️⃣ 查找或新增 Host（源节点和目标节点都进行 IP 查询）
        NodeDomain source = getOrCreateHost(addNetRelationVO.getSourceIp());
        NodeDomain destination = getOrCreateHost(addNetRelationVO.getDestinationIp());

        // 2️⃣ 先检查已有关系
        NetworkRelation relation = relationshipRepository.existsNetworkRelation(source.getNo(), addNetRelationVO.getProtocol(), destination.getNo(), addNetRelationVO.getDestinationPort());

        // 3️⃣ 判断是否已有完全相同的关系
        if (relation != null) {
            log.info("已有完全相同的关系，无需新增");
            return relation;
        } else {
            log.info("没有完全相同的关系，需要新增");
            // 3️⃣ 保存
            return relationshipRepository.addNetworkRelation(NetworkRelation.builder()
                    .sourceNo(source.getNo())
                    .sourcePort(addNetRelationVO.getSourcePort())
                    .protocol(addNetRelationVO.getProtocol())
                    .destinationNo(destination.getNo())
                    .destinationPort(addNetRelationVO.getDestinationPort())
                    .build());
        }
    }

    /**
     * 根据IP地址获取或创建主机节点
     *
     * @param ip 要查询或创建的主机节点的IP地址
     * @return 返回对应的主机节点对象，如果节点已存在则返回已有节点，否则返回新创建并保存的主机节点
     */
    private NodeDomain getOrCreateHost(String ip) {
        Optional<NodeDomain> oneByIpsIn = nodeRepository.getOneByIp(ip);
        if (oneByIpsIn.isPresent()) {
            return oneByIpsIn.get();
        } else {
            NodeDomain nodeDomain = new NodeDomain();
            nodeDomain.setIps(Arrays.asList(ip));
            return nodeRepository.save(nodeDomain);
        }
    }

    /**
     * 根据节点编号获取网络关系列表
     *
     * @param nodeNo 节点编号
     * @return 返回与给定节点编号相关的网络关系列表
     */
    public List<NetworkRelation> getNetworkRelationsByNodeNo(String nodeNo) {
        return relationshipRepository.getNetworkRelationsByNodeNo(nodeNo);
    }

    /**
     * 更新网络关系
     *
     * 该方法用于更新网络中的关系。给定源节点编号、旧目标节点编号和新目标节点编号，
     * 调用关系仓库（relationshipRepository）的updateNetworkRelation方法来更新网络关系。
     *
     * @param sourceNo        源节点编号
     * @param oldTargetNo     旧目标节点编号
     * @param newTargetNo     新目标节点编号
     * @return 更新后的网络关系对象
     */
    public NetworkRelation updateNetworkRelation(String sourceNo, String oldTargetNo, String newTargetNo) {
        return relationshipRepository.updateNetworkRelation(sourceNo, oldTargetNo, newTargetNo);
    }

}


